﻿using System.ComponentModel;
using System.Configuration;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Altairis.IdentityToolkit.Configuration;

namespace Altairis.IdentityToolkit.LiveId {

    /// <summary>
    /// Web control for displaying login and logout links for Windows Live ID service.
    /// </summary>
    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [ToolboxData("<{0}:LiveLogin runat=\"server\" />")]
    public class LiveLogin : CompositeControl {
        private ServiceElement config;
        private HyperLink actionLink;

        /// <summary>
        /// Initializes a new instance of the <see cref="LiveLogin"/> class.
        /// </summary>
        public LiveLogin() {
            // Read configuration
            var cs = ConfigurationManager.GetSection("altairis.identityToolkit/liveId") as LiveConfiguration;
            if (cs != null) this.config = cs.Service; // Design mode support

            // Set default property values
            this.Mode = LiveLoginMode.Auto;
            this.Action = LiveLoginAction.Auto;
            this.LoginText = "Login";
            this.LogoutText = "Logout";
        }

        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
        /// </summary>
        protected override void CreateChildControls() {
            // Create action link
            this.actionLink = new HyperLink();

            // Copy layout properties
            this.actionLink.CopyBaseAttributes(this);

            // Determine required action
            LiveLoginAction trueAction;
            if (this.Action == LiveLoginAction.Auto) {
                if (this.Context == null || !this.Context.Request.IsAuthenticated) trueAction = LiveLoginAction.Login;
                else trueAction = LiveLoginAction.Logout;
            }
            else {
                trueAction = this.Action;
            }

            if (trueAction == LiveLoginAction.Login) {
                // Prepare login link
                this.actionLink.NavigateUrl = this.GetLoginUrl();
                this.actionLink.Text = this.LoginText;
                if (this.Mode == LiveLoginMode.Auto) this.actionLink.ImageUrl = this.GetAutoImageUrl("signin.gif");
                else this.actionLink.ImageUrl = this.LoginImageUrl;
            }
            else {
                // Prepare logout link
                this.actionLink.NavigateUrl = this.GetLogoutUrl();
                this.actionLink.Text = this.LogoutText;
                if (this.Mode == LiveLoginMode.Auto) this.actionLink.ImageUrl = this.GetAutoImageUrl("signout.gif");
                else this.actionLink.ImageUrl = this.LogoutImageUrl;
            }

            if (this.Mode == LiveLoginMode.Auto) {
                // For localized auto images height is always 19px 
                // and width is undefined, because depends on language
                this.actionLink.Width = Unit.Empty;
                this.actionLink.Height = Unit.Pixel(19);
            }

            // Add action link to current
            this.Controls.Add(this.actionLink);
        }

        /// <summary>
        /// Writes the <see cref="T:System.Web.UI.WebControls.CompositeControl"/> content to the specified <see cref="T:System.Web.UI.HtmlTextWriter"/> object, for display on the client.
        /// </summary>
        /// <param name="writer">An <see cref="T:System.Web.UI.HtmlTextWriter"/> that represents the output stream to render HTML content on the client.</param>
        protected override void Render(HtmlTextWriter writer) {
            // Usually RenderBeginTag and RenderEndTag is called here,
            // but it adds unnecessary <span> tag to output code.
            this.RenderContents(writer);
        }

        /// <summary>
        /// Gets or sets the action performed by control.
        /// </summary>
        /// <value>The action performed by control.</value>
        [Category("Behavior"), Description("Action mode of the control."), DefaultValue(LiveLoginAction.Auto)]
        public LiveLoginAction Action { get; set; }

        /// <summary>
        /// Gets or sets the display mode.
        /// </summary>
        /// <value>The display mode.</value>
        [Category("Appearance"), Description("Display mode of the control."), DefaultValue(LiveLoginMode.Auto)]
        public LiveLoginMode Mode { get; set; }

        /// <summary>
        /// Gets or sets the text displayed when login action is to be performed.
        /// </summary>
        /// <value>The text displayed when login action is to be performed.</value>
        [Category("Appearance"), Description("Text to be displayed when login is needed."), DefaultValue("Login"), Localizable(true)]
        public string LoginText { get; set; }

        /// <summary>
        /// Gets or sets the text displayed when logout action is to be performed.
        /// </summary>
        /// <value>The text displayed when logout action is to be performed.</value>
        [Category("Appearance"), Description("Text to be displayed when logout is needed."), DefaultValue("Logout"), Localizable(true)]
        public string LogoutText { get; set; }

        /// <summary>
        /// Image to be displayed when DisplayMode is set to CustomImage and login is needed.
        /// </summary>
        /// <value>Image to be displayed when DisplayMode is set to CustomImage and login is needed.</value>
        [Category("Appearance"), Description("Image to be displayed when DisplayMode is set to CustomImage and login is needed."), UrlProperty]
        public string LoginImageUrl { get; set; }

        /// <summary>
        /// Image to be displayed when DisplayMode is set to CustomImage and logout is needed.
        /// </summary>
        /// <value>Image to be displayed when DisplayMode is set to CustomImage and logout is needed.</value>
        [Category("Appearance"), Description("Image to be displayed when DisplayMode is set to CustomImage and logout is needed."), UrlProperty]
        public string LogoutImageUrl { get; set; }

        private string GetAutoImageUrl(string fileName) {
            // In design mode, return English image using HTTP
            if (this.Context == null) return "http://www.passportimages.com/1033/" + fileName;

            // Generate image based on current UI culture and connection type.
            return string.Format("{0}://www.passportimages.com/{1}/{2}",
                this.Context.Request.IsSecureConnection ? "https" : "http",
                System.Threading.Thread.CurrentThread.CurrentUICulture.LCID,
                fileName);
        }

        private string GetLoginUrl() {
            if (this.config == null) return "#"; // Design mode support
            string url = string.Format("https://login.live.com/wlogin.srf?appid={0}&alg={1}", this.config.ApplicationId, this.config.Algorithm);
            if (!string.IsNullOrEmpty(Context.Request.QueryString["ReturnUrl"])) url += "&appctx=" + HttpUtility.UrlEncode(Context.Request.QueryString["ReturnUrl"]);
            return url;
        }

        private string GetLogoutUrl() {
            if (this.config == null) return "#"; // Design mode support
            return "https://login.live.com/logout.srf?appid=" + this.config.ApplicationId;
        }

    }

    /// <summary>The display mode of <see cref="LiveLogin"/> control.</summary>
    public enum LiveLoginMode {
        /// <summary>Standard Live ID login image, localized according to current UI culture.</summary>
        Auto,
        /// <summary>Specified display properties are used for displaying login and logout links.</summary>
        Custom
    }


    /// <summary>The operation mode of <see cref="LiveLogin"/> control.</summary>
    public enum LiveLoginAction {
        /// <summary>Display login interface.</summary>
        Login,
        /// <summary>Display logout interface</summary>
        Logout,
        /// <summary>Display automatically login/logout interface based on login status.</summary>
        Auto
    }

}
